#ifdef __STRICT_ANSI__
#	undef __STRICT_ANSI__ 
#endif
#include "String.h"
#include <cwchar>

#ifdef RZ_COMPILER_MSVC
#	define _RZ_STRING_SPRINTF(buff, fmt, ...)			sprintf_s(buff, fmt, __VA_ARGS__)
#	define _RZ_STRING_SWPRINTF(buff, fmt, ...)			swprintf_s(buff, fmt, __VA_ARGS__)

#	define _RZ_STRING_VSCPRINTF(fmt, args)				_vscprintf(fmt, args)
#	define _RZ_STRING_VSCWPRINTF(fmt, args)				_vscwprintf(format, args)

#	define _RZ_STRING_VSPRINTF(buff, len, fmt, args)		vsprintf_s(buff, len, fmt, args)
#	define _RZ_STRING_VSWPRINTF(buff, len, fmt, args)	vswprintf_s(buff, len, fmt, args)
#else
#	define _RZ_STRING_SPRINTF(buff, fmt, ...)			sprintf(buff, fmt, __VA_ARGS__)
#	define _RZ_STRING_SWPRINTF(buff, fmt, ...)			swprintf(buff, fmt, __VA_ARGS__)

#	define _RZ_STRING_VSCPRINTF(fmt, args)				vsprintf(NULL, fmt, args)
#	define _RZ_STRING_VSCWPRINTF(fmt, args)				vswprintf(NULL, format, args)

#	define _RZ_STRING_VSPRINTF(buff, len, fmt, args)		vsprintf(buff, fmt, args)
#	define _RZ_STRING_VSWPRINTF(buff, len, fmt, args)	vswprintf(buff, fmt, args)
#endif

#define _RZ_STRING_CONVERT_FN_CHAR(op)	\
	char tmpBuff[32];					\
	_RZ_STRING_SPRINTF(tmpBuff, op, s);			\
	return BasicString<char>(tmpBuff)

#define _RZ_STRING_CONVERT_FN_WCHAR(op) 	\
	wchar_t tmpBuff[32];				\
	_RZ_STRING_SWPRINTF(tmpBuff, L##op, s);		\
	return BasicString<wchar_t>(tmpBuff)


namespace Rz {

template <> const char* BasicString<char>::Whitespaces = " \t\f\v\n\r";
template <> const wchar_t* BasicString<wchar_t>::Whitespaces = L" \t\f\v\n\r";
template <> const char* BasicString<char>::_trueStr = "true";
template <> const wchar_t* BasicString<wchar_t>::_trueStr = L"true";

template <>
BasicString<char> BasicString<char>::From(s32 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%i");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(s32 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%i");
}

template <>
BasicString<char> BasicString<char>::From(u32 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%u");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(u32 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%u");
}

template <>
BasicString<char> BasicString<char>::From(s64 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%lld");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(s64 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%lld");
}

template <>
BasicString<char> BasicString<char>::From(u64 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%llu");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(u64 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%llu");
}

template <>
BasicString<char> BasicString<char>::From(f32 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%f");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(f32 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%f");
}

template <>
BasicString<char> BasicString<char>::From(f64 s)
{
	_RZ_STRING_CONVERT_FN_CHAR("%lf");
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::From(f64 s)
{
	_RZ_STRING_CONVERT_FN_WCHAR("%lf");
}

template <>
BasicString<char> BasicString<char>::Format(const char* format, ...) 
{
	va_list argList;
	va_start(argList, format);

	BasicString<char> result = FormatV(format, argList);

	return result;
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::Format(const wchar_t* format, ...) 
{
	va_list argList;
	va_start(argList, format);

	BasicString<wchar_t> result = FormatV(format, argList);

	va_end(argList);

	return result;
}

template <>
s32 BasicString<char>::CFormat(char* dest, u32 bufferSize, const char* format, ...) 
{
	va_list argList;
	va_start(argList, format);

	s32 result = CFormatV(dest, bufferSize, format, argList);

	va_end(argList);

	return result;
}

template <>
s32 BasicString<wchar_t>::CFormat(wchar_t* dest, u32 bufferSize, const wchar_t* format, ...) 
{
	va_list argList;
	va_start(argList, format);

	s32 result = CFormatV(dest, bufferSize, format, argList);

	va_end(argList);

	return result;
}

template <>
BasicString<char> BasicString<char>::FormatV(const char* format, va_list list)
{
	s32 len = _RZ_STRING_VSCPRINTF(format, list) + 1;

	char *buff = new char[len];

	_RZ_STRING_VSPRINTF(buff, len, format, list);

	BasicString<char> result(buff);

	delete[] buff;

	return result;
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::FormatV(const wchar_t* format, va_list list)
{
	s32 len = _RZ_STRING_VSCWPRINTF(format, list) + 1;

	wchar_t *buff = new wchar_t[len];

	_RZ_STRING_VSWPRINTF(buff, len, format, list);

	BasicString<wchar_t> result(buff);

	delete[] buff;

	return result;
}

template <>
s32 BasicString<char>::CFormatV(char* dest, u32 bufferSize, const char* format, va_list list)
{
#ifdef RZ_COMPILER_MSVC
#	pragma warning (push)
#	pragma warning (disable : 4996)
#endif

	return static_cast<s32>(vsnprintf(dest, bufferSize, format, list));

#ifdef RZ_COMPILER_MSVC
#	pragma warning (pop)
#endif
}

template <>
s32 BasicString<wchar_t>::CFormatV(wchar_t* dest, u32 bufferSize, const wchar_t* format, va_list list)
{
	return static_cast<s32>(_RZ_STRING_VSWPRINTF(dest, bufferSize, format, list));
}


template <>
BasicString<wchar_t> BasicString<char>::ToWideChar() const
{
	size_t buffLen = MultiByte::GetFinalStringLength(_string.c_str());

	wchar_t *tmp = new wchar_t[buffLen + sizeof(wchar_t)];

	MultiByte::ToWideChar(_string.c_str(), tmp, buffLen);

	BasicString<wchar_t> r(tmp);

	delete[] tmp;

	return r;
}

template <>
BasicString<wchar_t> BasicString<wchar_t>::ToWideChar() const
{
	return (*this);
}

template <>
BasicString<char> BasicString<char>::ToMultiByte() const
{
	return (*this);
}

template <>
BasicString<char> BasicString<wchar_t>::ToMultiByte() const
{
	size_t buffLen = WideChar::GetFinalStringLength(_string.c_str());

	char* tmp = new char[buffLen + sizeof(char)];

	WideChar::ToMultiByte(_string.c_str(), tmp, buffLen);

	BasicString<char> r(tmp);

	delete[] tmp;

	return r;
}

template <>
BasicString<char>::SizeType BasicString<char>::Internal_StrLen(const char* str) const 
{
	return static_cast<SizeType>(strlen(str));
}

template <>
BasicString<wchar_t>::SizeType BasicString<wchar_t>::Internal_StrLen(const wchar_t* str) const
{
	return static_cast<SizeType>(wcslen(str));
}

}
